メインコンテンツまでスキップ

SLMPv2 Library User Manual

1. 概要 (Overview)

SLMP (Seamless Message Protocol) は、制御機器をシームレスに接続するための、ベンダーフリーな共通プロトコルで、CC-Link 協会が管理しています。

本ライブラリ (SLMPv2 Library) は、Javaアプリケーションから三菱電機製PLCとSLMP通信を行うために開発されました。TCP/IPおよびUDP/IPの両方をサポートし、PLCのデバイスに対して直感的で型安全なAPIを提供します。

現在、以下のSLMPコマンドをサポートしています。

  • 一括読み出し (0x0401): 連続したデバイス領域のデータをまとめて読み出します。
  • 一括書き込み (0x1401): 連続したデバイス領域にデータをまとめて書き込みます。
  • ランダム読み出し (0x0403): 非連続な複数のデバイスからデータを個別に読み出します。
  • ランダム書き込み (0x1402): 非連続な複数のデバイスにデータを個別に書き込みます。

2. はじめに (Getting Started)

このライブラリを使い始めるには、2つの方法があります。

  1. 実行可能なサンプルアプリケーションで試す (推奨): まずはライブラリの動作を体感したい方向けです。
  2. ご自身のプロジェクトに組み込む: すぐに自身のアプリケーション開発を始めたい方向けです。

2.1. 実行可能なサンプルアプリケーションで試す (Try with a Runnable Sample)

このライブラリには、基本的な使い方をすぐに試せる実行可能なサンプルアプリケーション SlmpFrameTester が同梱されています。 このアプリケーションは、設定ファイルに基づいてPLCに接続し、D100デバイスへの一括書き込みと、その後の読み出し・検証を行います。

ビルド方法 (How to Build)

サンプルアプリケーションをビルドする前に、プロジェクトのルートディレクトリで以下のコマンドを実行し、すべてのモジュールをローカルリポジトリにインストールしてください。

mvn clean install

これにより、SlmpFrameTesterが依存するライブラリを正しく解決できるようになります。

サンプルアプリケーションをビルドするには、Mavenが必要です。プロジェクトのルートディレクトリで以下のコマンドを実行してください。

# SlmpFrameTester プロジェクトをビルド
mvn -f SlmpFrameTester/pom.xml clean package

ビルドが成功すると、SlmpFrameTester/target/ ディレクトリに slmpframetester-1.00.jar という実行可能なJARファイルと、依存ライブラリが格納された lib ディレクトリが生成されます。

設定 (Configuration)

PLCへの接続情報は、SlmpFrameTester/config.properties ファイルで設定します。アプリケーションを実行する前に、ご自身の環境に合わせてこのファイルを編集してください。

# Test mode: 'production' for real PLC, 'test' for mock.
mode=production

# PLC Connection Settings
slmp.host=192.168.4.100 # 接続先PLCのIPアドレス
slmp.port=8000 # 接続先PLCのポート番号
slmp.protocol=udp # tcp または udp
slmp.timeout=5000 # タイムアウト時間 (ミリ秒)

実行方法 (How to Run)

ビルドが完了したら、以下のコマンドでサンプルアプリケーションを実行できます。

java -jar SlmpFrameTester/target/slmpframetester-1.0.0.jar

実行すると、コンソールに通信の詳細(送信フレーム、受信データなど)が出力され、ライブラリがPLCとどのように通信しているかを具体的に確認することができます。

--- SLMPv2 Sample Application Start ---
PLC接続設定: udp://192.168.4.100:8000 (Timeout: 5000ms)

--- 書き込みフェーズ ---
送信データ: [1000, 2000, 3000]

--- 送信フレーム (書き込み) ---
全体 (16進数): 50 00 00 FF FF 03 00 12 00 00 00 01 14 00 00 64 00 00 A8 03 00 E8 03 D0 07 B8 0B
フィールドごと (16進数):
ネットワーク番号: 00
PC番号: FF
要求先モジュールI/O番号: 03FF
要求先マルチドロップ局番: 00
監視タイマ: 0000
コマンド: 1401
サブコマンド: 0000
受信応答ステータスコード (書き込み): 0
SUCCESS: D100へのワードデータ一括書き込みが成功しました。

--- 読み出しフェーズ ---

--- 送信フレーム (読み出し) ---
全体 (16進数): 50 00 00 FF FF 03 00 0C 00 00 00 01 04 00 00 64 00 00 A8 03 00
フィールドごと (16進数):
ネットワーク番号: 00
PC番号: FF
要求先モジュールI/O番号: 03FF
要求先マルチドロップ局番: 00
監視タイマ: 0000
コマンド: 0401
サブコマンド: 0000
受信応答ステータスコード (読み出し): 0
受信データ (読み出し):
[0]: 1000 (0x03E8)
[1]: 2000 (0x07D0)
[2]: 3000 (0x0BB8)
SUCCESS: D100からのワードデータ一括読み出しと検証が完了しました。
--- SLMPv2 Sample Application End ---

PLCに接続できないと次のメッセージが表示されます。

--- SLMPv2 Sample Application Start ---
PLC接続設定: udp://192.168.4.100:8000 (Timeout: 5000ms)
アプリケーション実行中に例外が発生しました: java.net.SocketTimeoutException: Connect timed out
java.io.UncheckedIOException: java.net.SocketTimeoutException: Connect timed out
at plc.slmp.client.DefaultSlmpClient$DefaultBuilder.build(DefaultSlmpClient.java:193)
at plc.slmp.slmpframetester.Main.main(Main.java:43)
Caused by: java.net.SocketTimeoutException: Connect timed out
at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:546)
at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:592)
at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327)
at java.base/java.net.Socket.connect(Socket.java:751)
at plc.transport.SyncTcpTransport.<init>(SyncTcpTransport.java:68)
at plc.slmp.client.DefaultSlmpClient$DefaultBuilder.build(DefaultSlmpClient.java:185)
... 1 more
--- SLMPv2 Sample Application End ---

2.2. ご自身のプロジェクトに組み込む (Integrate into Your Project)

ご自身のMavenプロジェクトでこのライブラリを使用するには、pom.xmlに以下の依存関係を追加してください。

(注: このライブラリは現在Maven Centralに登録されていません。使用するには、まずプロジェクトのルートで mvn clean install を実行し、ライブラリをローカルリポジトリにインストールする必要があります。)

<dependency>
<groupId>plc.slmp</groupId>
<artifactId>SlmpFrame</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>plc.slmp</groupId>
<artifactId>ByteFormatUtility</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

3. 基本的な使い方 (Basic Usage)

3.1. 接続設定 (Connection Configuration)

SlmpClientの接続設定には、プログラムで直接指定する方法と、設定ファイルから読み込む方法の2つがあります。

3.1.1. プログラムでの直接指定 (推奨)

最も安全で推奨される方法は、SlmpClient.builder() を使用して、コード内で接続情報を明示的に指定することです。これにより、アプリケーションの動作がコードから明確に理解でき、環境による意図しない挙動を防ぐことができます。

SlmpClientjava.io.Closeableを実装しているため、try-with-resources構文を使用することが推奨されます。

// TCPクライアントの例
String host = "192.168.1.10";
int port = 5007;
int timeout = 5000; // タイムアウトを5秒に設定
try (SlmpClient client = SlmpClient.builder()
.tcp(host, port)
.timeout(timeout)
.build()) {
// PLCとの通信処理
}

// UDPクライアントの例
String host = "192.168.1.10";
int port = 5006;
try (SlmpClient client = SlmpClient.builder().udp(host, port).build()) {
// PLCとの通信処理
}

3.1.2. 設定ファイルからの読み込み

ライブラリには、クラスパス上の config.properties ファイルから設定を読み込む仕組みも用意されています。これは、アプリケーションを再コンパイルせずに接続情報を変更したい場合に便利です。

1. config.properties の準備

まず、src/main/resources フォルダに config.properties という名前のファイルを作成し、以下のように接続情報を記述します。

# SLMP Client Default Settings
slmp.host=192.168.4.100
slmp.port=8000
slmp.protocol=udp
slmp.timeout=5000

2. 設定を読み込むコード

PropertiesFileConfigurationProviderDefaultConfiguration を使って設定を読み込み、SlmpClient を構築します。

import plc.slmp.client.SlmpClient;
import plc.slmp.config.DefaultConfiguration;
import plc.slmp.config.SlmpConfiguration;
import plc.slmp.config.provider.ConfigurationProvider;
import plc.slmp.config.provider.PropertiesFileConfigurationProvider;
import java.util.Optional;

// ...

try {
// 1. config.properties から設定を読み込むプロバイダーを作成
ConfigurationProvider propProvider = new PropertiesFileConfigurationProvider("config.properties");

// 2. プロバイダーを元に設定オブジェクトを作成
SlmpConfiguration config = new DefaultConfiguration(propProvider);

// 3. 設定値を取得
String host = config.getHost().orElse("localhost"); // 見つからない場合のデフォルト値
int port = config.getPort().orElse(8000);
String protocol = config.getProtocol().orElse("udp");
int timeout = config.getTimeout().orElse(5000);

// 4. 取得した設定を使ってSlmpClientをビルド
SlmpClient.Builder builder = SlmpClient.builder().timeout(timeout);

if ("tcp".equalsIgnoreCase(protocol)) {
builder.tcp(host, port);
} else {
builder.udp(host, port);
}

try (SlmpClient client = builder.build()) {
System.out.println("Successfully created client from config.properties.");
System.out.println("Protocol: " + protocol + ", Host: " + host + ", Port: " + port);

// PLCとの通信処理
}
} catch (Exception e) {
e.printStackTrace();
}

3.2. 基本的な通信フロー (Basic Communication Flow)

PLCとの通信は、以下のステップで行います。

  1. リクエストオブジェクトの作成: ReadRequest, WriteRequestなど、実行したい操作に応じたリクエストを作成します。
  2. コマンドの実行: client.read(...)client.write(...) などのメソッドでリクエストを送信します。
  3. レスポンスの取得: 戻り値として SlmpResponse オブジェクトを受け取ります。
  4. 終了コードの確認: response.getEndCode() を確認し、処理が正常に完了したか(0であるか)を判断します。
  5. 応答データの処理: 正常終了していれば、response.getBody() で応答データを取得し、処理します。

以下は、一括読み出しの簡単な例です。

import plc.slmp.client.SlmpClient;
import plc.slmp.client.body.BodyHandlers;
import plc.slmp.client.response.SlmpResponse;
import plc.slmp.slmpframe.Device;
import plc.slmp.slmpframe.SlmpDeviceType;
import plc.slmp.slmpframe.data.PlcData;
import plc.slmp.slmpframe.request.ReadRequest;
import java.util.List;

// D100から連続して3ワード分のデータを読み出す
try (SlmpClient client = SlmpClient.builder().tcp("192.168.1.10", 5007).build()) {
// 1. リクエストの作成
ReadRequest request = ReadRequest.createWordRead(new Device(SlmpDeviceType.D, 100)).readWord(3);

// 2. コマンドの実行 & 3. レスポンスの取得
SlmpResponse<List<PlcData>> response = client.read(request, BodyHandlers.ofPlcData());

// 4. 終了コードの確認
if (response.getEndCode() == 0) {
System.out.println("Read successful!");
// 5. 応答データの処理
List<PlcData> data = response.getBody();
System.out.println("Response data: " + data);
} else {
System.err.println("PLC Error Code: " + Integer.toHexString(response.getEndCode()));
}
} catch (Exception e) {
// 通信例外の処理
e.printStackTrace();
}

3.3. 各コマンドの詳細 (Details of Each Command)

3.3.1. 一括読み出し (Bulk Read)

あるデバイスアドレスから連続した領域をまとめて読み出す場合に使用します。

ワードデバイスの場合 ReadRequest.createWordRead()でリクエストを作成します。

// D100から連続して3ワード分のデータを読み出すリクエスト
ReadRequest request = ReadRequest.createWordRead(new Device(SlmpDeviceType.D, 100))
.readWord(3); // D100, D101, D102 を読み出す

ビットデバイスの場合 ReadRequest.createBitRead()でリクエストを作成します。

// M100から連続して4点のビットデータを読み出すリクエスト
ReadRequest request = ReadRequest.createBitRead(new Device(SlmpDeviceType.M, 100))
.readBit(4); // M100, M101, M102, M103 を読み出す

3.3.2. 一括書き込み (Bulk Write)

あるデバイスアドレスから連続した領域にまとめて書き込む場合に使用します。

ワードデバイスの場合 WriteRequest.createWordWrite()でリクエストを作成します。


writeWord()による個別指定

// D300から連続して3ワード分のデータを書き込むリクエスト
WriteRequest request = WriteRequest.createWordWrite(new Device(SlmpDeviceType.D, 300))
.writeWord(111)
.writeWord(222)
.writeDWord(5678); // ダブルワードも混在可能

writeAll()によるリストでの一括指定

java.util.Listを使って、書き込むデータをまとめて指定することもできます。これにより、動的に書き込み点数を変更するような場合に便利です。

// 書き込むデータのリストを作成
List<PlcData> writeData = new ArrayList<>();
writeData.add(new WordData(111));
writeData.add(new WordData(222));
writeData.add(new DWordData(5678)); // 型の異なるデータもリストに含めることが可能

// リストを渡してリクエストを作成
WriteRequest request = WriteRequest.createWordWrite(new Device(SlmpDeviceType.D, 300))
.writeAll(writeData);

ビットデバイスの場合 WriteRequest.createBitWrite()でリクエストを作成します。値はON=1, OFF=0で指定します。

// M200から連続して4点に書き込むリクエスト (ON, OFF, ON, ON)
WriteRequest request = WriteRequest.createBitWrite(new Device(SlmpDeviceType.M, 200))
.writeBit(1)
.writeBit(0)
.writeBit(1)
.writeBit(1);

3.3.3. ランダム読み出し (Random Read)

非連続のデバイスを一度にまとめて読み出す場合に使用します。RandomReadRequest.create()でリクエストを作成します。


readWord()/readDWord()による個別指定

// D100 (ワード) と D200 (ダブルワード) を読み出すリクエスト
RandomReadRequest request = RandomReadRequest.create()
.readWord(new Device(SlmpDeviceType.D, 100))
.readDWord(new Device(SlmpDeviceType.D, 200));

readAllWords()/readAllDWords()によるリストでの一括指定

java.util.Listを使って、読み出すデバイスをまとめて指定することもできます。

// ワード読み出しのリストを作成
List<Device> wordDevices = new ArrayList<>();
wordDevices.add(new Device(SlmpDeviceType.D, 100));
wordDevices.add(new Device(SlmpDeviceType.M, 500));

// ダブルワード読み出しのリストを作成
List<Device> dwordDevices = new ArrayList<>();
dwordDevices.add(new Device(SlmpDeviceType.D, 200));
dwordDevices.add(new Device(SlmpDeviceType.W, 400));

// リストを渡してリクエストを作成
RandomReadRequest request = RandomReadRequest.create()
.readAllWords(wordDevices)
.readAllDWords(dwordDevices);

3.3.4. ランダム書き込み (Random Write)

非連続のデバイスに一度にまとめて書き込む場合に使用します。RandomWriteRequest.create()でリクエストを作成します。


writeWord()/writeDWord()による個別指定

// D100に1234, D200に567890を書き込むリクエスト
RandomWriteRequest request = RandomWriteRequest.create()
.writeWord(new Device(SlmpDeviceType.D, 100), new WordData(1234))
.writeDWord(new Device(SlmpDeviceType.D, 200), new DWordData(567890));

writeAllWords()/writeAllDWords()によるリストでの一括指定

java.util.Listを使って、書き込むデバイスとデータのペア(WordWriteEntryまたはDWordWriteEntry)をまとめて指定することもできます。

// ワード書き込みのリストを作成
List<RandomWriteRequest.WordWriteEntry> wordEntries = new ArrayList<>();
wordEntries.add(new RandomWriteRequest.WordWriteEntry(new Device(SlmpDeviceType.D, 100), new WordData(111)));
wordEntries.add(new RandomWriteRequest.WordWriteEntry(new Device(SlmpDeviceType.M, 500), new WordData(222)));

// ダブルワード書き込みのリストを作成
List<RandomWriteRequest.DWordWriteEntry> dwordEntries = new ArrayList<>();
dwordEntries.add(new RandomWriteRequest.DWordWriteEntry(new Device(SlmpDeviceType.D, 200), new DWordData(33333)));
dwordEntries.add(new RandomWriteRequest.DWordWriteEntry(new Device(SlmpDeviceType.W, 400), new DWordData(44444)));

// リストを渡してリクエストを作成
RandomWriteRequest request = RandomWriteRequest.create()
.writeAllWords(wordEntries)
.writeAllDWords(dwordEntries);

4. 応答とエラーハンドリング (Response and Error Handling)

4.1. 正常応答とエラー応答

すべてのコマンド実行メソッドは SlmpResponse オブジェクトを返します。

  • response.getEndCode(): PLCからの終了コードを取得します。0が正常終了です。0以外の場合は、PLC側で何らかのエラーが発生したことを示します。
  • response.getBody(): BodyHandlerによって変換された応答データを取得します。

4.2. チェック例外

コマンド実行時には、以下のチェック例外が発生する可能性があります。これらはtry-catchブロックで処理する必要があります。

  • plc.transport.exception.CommunicationTimeoutException

    • 原因: PLCとの通信中に、設定されたタイムアウト時間内に応答がなかった場合にスローされます。ネットワークの遅延やPLCの高負荷が考えられます。
    • 処置: リトライ処理を実装するか、SlmpClient.builder().timeout()でタイムアウト値を長めに設定することを検討してください。
  • plc.slmp.slmpframe.exception.SlmpException

    • 原因: SLMPプロトコルレベルでのエラーを示す、このライブラリのカスタムチェック例外の基底クラスです。例えば、PLCから返された終了コードがslmp_errors.propertiesで"user"エラーとして定義されている場合(例: デバイス指定の不正 0xC05B)、この例外のサブクラスがスローされます。
    • 処置: getMessage()で得られるエラー内容を確認し、リクエストのパラメータ(デバイスアドレスなど)が正しいか確認してください。
  • java.io.IOException

    • 原因: タイムアウト以外の、より低レベルなI/Oエラーが発生した場合にスローされます。例えば、ホストが見つからない、ネットワーク接続が切断された、などが該当します。
    • 処置: ネットワーク設定や物理的な接続を確認してください。

5. デバイス指定 (Device Specification)

デバイスは plc.slmp.slmpframe.Device クラスで表現します。

new Device(SlmpDeviceType deviceType, int address)

  • deviceType: SlmpDeviceType enumでデバイス種別を指定します。
  • address: デバイス番号を指定します。

利用可能な SlmpDeviceType は以下の通りです。

Enumデバイスコード説明 (ビット/ワード)
SM0x91特殊リレー (ビット)
SD0xA9特殊レジスタ (ワード)
X0x9C入力 (ビット)
Y0x9D出力 (ビット)
M0x90内部リレー (ビット)
L0x92ラッチリレー (ビット)
F0x93アナンシエータ (ビット)
V0x94エッジリレー (ビット)
B0xA0リンクリレー (ビット)
S0x98ステップリレー (ビット)
TS0xC1タイマ接点 (ビット)
TC0xC0タイマコイル (ビット)
STS0xC7積算タイマ接点 (ビット)
STC0xC6積算タイマコイル (ビット)
CS0xC4カウンタ接点 (ビット)
CC0xC3カウンタコイル (ビット)
D0xA8データレジスタ (ワード)
W0xB4リンクレジスタ (ワード)
TN0xC2タイマ現在値 (ワード)
STN0xC8積算タイマ現在値 (ワード)
CN0xC5カウンタ現在値 (ワード)
G0xABファイルレジスタ (ワード)

6. 設定ファイル (Configuration Files)

SlmpFrame/src/main/resources には、ライブラリの挙動を制御する設定ファイルが含まれています。

config.properties

ライブラリのデフォルトの接続設定を定義します。

  • slmp.host: 接続先PLCのデフォルトIPアドレス。
  • slmp.port: 接続先PLCのデフォルトポート番号。
  • slmp.protocol: デフォルトの通信プロトコル (tcp または udp)。
  • slmp.timeout: デフォルトの通信タイムアウト時間 (ミリ秒)。

注: ここでの設定は、SlmpClient.builder()で何も指定しなかった場合のフォールバック値です。アプリケーションコード内でbuilder()メソッドを使って明示的に設定する方が、より安全で確実です。

slmp_errors.properties

PLCが返す終了コード(End Code)に対応するエラーメッセージ、原因、および対処法を定義しています。 このファイルはライブラリ内部で使用され、PLCからのエラー応答時にスローされるSlmpExceptionのメッセージなどを生成します。 通常、ユーザーがこのファイルを変更する必要はありませんが、エラー内容を詳しく知りたい場合の参考としてください。

データフォーマット

各エラーコードは、C051のような16進数4桁のキーで定義されます。キーに続けて、以下の情報をドット区切りで指定します。

  • description (必須): エラーの内容と原因を説明します。
  • type (必須): スローされる例外の種別を指定します。
    • user: SlmpExceptionのサブクラスであるチェック例外 (例: SlmpUserException)。主にリクエスト内容の誤りなど、ユーザー側の問題に起因します。
    • logic: SlmpExceptionのサブクラスである非チェック例外 (例: SlmpLogicException)。主にライブラリ内部の論理的な問題に起因します。
  • action.(n) (任意): エラーへの対処法を.1, .2, ...という連番で複数記述できます。
  • supported_frames (任意): このエラーコードが関連するSLMPフレーム種別をカンマ区切りで示します (例: 3E,1E)。

定義例

以下は、0xC05B(要求デバイスの指定が不正)エラーの定義例です。

#============================================================
# 終了コード 0xC05B
#============================================================
C05B.description=要求デバイスの指定が不正です。
C05B.type=user
C05B.action.1=デバイス番号が、使用するCPUユニットのデバイス範囲を超えています。
C05B.action.2=デバイス種別が、使用するCPUユニットでサポートされていません。
C05B.supported_frames=3E,1E

7. 完全なサンプルコード (TCP)

import plc.slmp.client.SlmpClient;
import plc.slmp.client.body.BodyHandlers;
import plc.slmp.client.response.SlmpResponse;
import plc.slmp.slmpframe.Device;
import plc.slmp.slmpframe.SlmpDeviceType;
import plc.slmp.slmpframe.data.*;
import plc.slmp.slmpframe.request.*;
import plc.slmp.slmpframe.response.RandomReadResponse;
import java.util.List;

public class SlmpTcpSample {

public static void main(String[] args) {
String host = "192.168.1.10"; // PLCのIPアドレス
int port = 5007; // TCP用のポート番号

try (SlmpClient client = SlmpClient.builder().tcp(host, port).timeout(5000).build()) {

// --- 1. ワード一括書き込み ---
System.out.println("--- TCP: Bulk Word Write ---");
WriteRequest bulkWordWriteReq = WriteRequest.createWordWrite(new Device(SlmpDeviceType.D, 300))
.writeWord(111).writeWord(222);
client.write(bulkWordWriteReq, BodyHandlers.ofDiscarding());

// --- 2. ワード一括読み出し ---
System.out.println("\n--- TCP: Bulk Word Read ---");
ReadRequest bulkWordReadReq = ReadRequest.createWordRead(new Device(SlmpDeviceType.D, 300)).readWord(2);
SlmpResponse<List<PlcData>> bulkWordReadRes = client.read(bulkWordReadReq, BodyHandlers.ofPlcData());
if (bulkWordReadRes.getEndCode() == 0) System.out.println("Read successful: " + bulkWordReadRes.getBody());

// --- 3. ビット一括書き込み ---
System.out.println("\n--- TCP: Bulk Bit Write ---");
WriteRequest bulkBitWriteReq = WriteRequest.createBitWrite(new Device(SlmpDeviceType.M, 100))
.writeBit(1).writeBit(0).writeBit(1);
client.write(bulkBitWriteReq, BodyHandlers.ofDiscarding());

// --- 4. ビット一括読み出し ---
System.out.println("\n--- TCP: Bulk Bit Read ---");
ReadRequest bulkBitReadReq = ReadRequest.createBitRead(new Device(SlmpDeviceType.M, 100)).readBit(3);
SlmpResponse<List<PlcData>> bulkBitReadRes = client.read(bulkBitReadReq, BodyHandlers.ofPlcData());
if (bulkBitReadRes.getEndCode() == 0) System.out.println("Read successful: " + bulkBitReadRes.getBody());

// --- 5. ランダム書き込み ---
System.out.println("\n--- TCP: Random Write ---");
RandomWriteRequest randWriteReq = RandomWriteRequest.create()
.writeWord(new Device(SlmpDeviceType.D, 100), new WordData(1234))
.writeDWord(new Device(SlmpDeviceType.D, 200), new DWordData(567890));
client.write(randWriteReq, BodyHandlers.ofDiscarding());

// --- 6. ランダム読み出し ---
System.out.println("\n--- TCP: Random Read ---");
RandomReadRequest randReadReq = RandomReadRequest.create()
.readWord(new Device(SlmpDeviceType.D, 100))
.readDWord(new Device(SlmpDeviceType.D, 200));
SlmpResponse<RandomReadResponse> randReadRes = client.randomRead(randReadReq, BodyHandlers.ofRandomRead(randReadReq));
if (randReadRes.getEndCode() == 0) System.out.println("Read successful: " + randReadRes.getBody());

} catch (Exception e) {
e.printStackTrace();
}
}
}

8. 完全なサンプルコード (UDP)

import plc.slmp.client.SlmpClient;
import plc.slmp.client.body.BodyHandlers;
import plc.slmp.client.response.SlmpResponse;
import plc.slmp.slmpframe.Device;
import plc.slmp.slmpframe.SlmpDeviceType;
import plc.slmp.slmpframe.data.*;
import plc.slmp.slmpframe.request.*;
import plc.slmp.slmpframe.response.RandomReadResponse;
import java.util.List;

public class SlmpUdpSample {

public static void main(String[] args) {
String host = "192.168.1.10"; // PLCのIPアドレス
int port = 5006; // UDP用のポート番号

try (SlmpClient client = SlmpClient.builder().udp(host, port).timeout(5000).build()) {

// --- 1. ワード一括書き込み ---
System.out.println("--- UDP: Bulk Word Write ---");
WriteRequest bulkWordWriteReq = WriteRequest.createWordWrite(new Device(SlmpDeviceType.D, 300))
.writeWord(444).writeWord(555);
client.write(bulkWordWriteReq, BodyHandlers.ofDiscarding());

// --- 2. ワード一括読み出し ---
System.out.println("\n--- UDP: Bulk Word Read ---");
ReadRequest bulkWordReadReq = ReadRequest.createWordRead(new Device(SlmpDeviceType.D, 300)).readWord(2);
SlmpResponse<List<PlcData>> bulkWordReadRes = client.read(bulkWordReadReq, BodyHandlers.ofPlcData());
if (bulkWordReadRes.getEndCode() == 0) System.out.println("Read successful: " + bulkWordReadRes.getBody());

// --- 3. ビット一括書き込み ---
System.out.println("\n--- UDP: Bulk Bit Write ---");
WriteRequest bulkBitWriteReq = WriteRequest.createBitWrite(new Device(SlmpDeviceType.M, 200))
.writeBit(0).writeBit(1).writeBit(0);
client.write(bulkBitWriteReq, BodyHandlers.ofDiscarding());

// --- 4. ビット一括読み出し ---
System.out.println("\n--- UDP: Bulk Bit Read ---");
ReadRequest bulkBitReadReq = ReadRequest.createBitRead(new Device(SlmpDeviceType.M, 200)).readBit(3);
SlmpResponse<List<PlcData>> bulkBitReadRes = client.read(bulkBitReadReq, BodyHandlers.ofPlcData());
if (bulkBitReadRes.getEndCode() == 0) System.out.println("Read successful: " + bulkBitReadRes.getBody());

// --- 5. ランダム書き込み ---
System.out.println("\n--- UDP: Random Write ---");
RandomWriteRequest randWriteReq = RandomWriteRequest.create()
.writeWord(new Device(SlmpDeviceType.D, 100), new WordData(4321))
.writeDWord(new Device(SlmpDeviceType.D, 200), new DWordData(987654));
client.write(randWriteReq, BodyHandlers.ofDiscarding());

// --- 6. ランダム読み出し ---
System.out.println("\n--- UDP: Random Read ---");
RandomReadRequest randReadReq = RandomReadRequest.create()
.readWord(new Device(SlmpDeviceType.D, 100))
.readDWord(new Device(SlmpDeviceType.D, 200));
SlmpResponse<RandomReadResponse> randReadRes = client.randomRead(randReadReq, BodyHandlers.ofRandomRead(randReadReq));
if (randReadRes.getEndCode() == 0) System.out.println("Read successful: " + randReadRes.getBody());

} catch (Exception e) {
e.printStackTrace();
}
}
}